home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.04 Apr 90 / Messenger Files / Messenger.c next >
Encoding:
C/C++ Source or Header  |  1990-01-30  |  20.9 KB  |  718 lines  |  [TEXT/KAHL]

  1. /******************************
  2. File Messenger.c
  3. By Kirk Chase with ideas from Paul Potts
  4. Created 9/20/89
  5.  
  6. Useful routines for dialogs
  7. *****************************/
  8.  
  9. #include "Messenger.h"
  10. #include "pascal.h"
  11. #include <string.h>
  12.  
  13. /* variables available globally*/
  14. DialogInfo MInfo;
  15. int menu_hieght;
  16.  
  17. /* PROTOTYPES */
  18. /* GLOBAL: void MenuBar_Hieght(void)
  19.     used to return menu bar height */
  20.  
  21. /* GLOBAL: void GetMInfo(DialogInfoPointer theMInfo)
  22.     used to get current MInfo state */
  23.  
  24. /* GLOBAL: void SetMInfo(DialogInfo theMInfo)
  25.     used to set current MInfo state; use like GetPort() and SetPort() with GetMInfo() */
  26.     
  27. /* GLOBAL: void SetUpButtons(int numButtons, short theDefault, char *b1, char *b2, char *b3, char *cq);
  28.      used to set up button info in MInfo */
  29.      
  30. /* GLOBAL: void SetUpRects(int dHor, int dVer, int bHor, int bVer)
  31.     used to set up rectangles in MInfo */
  32.      
  33. /* GLOBAL: void PositionRect(Rect *smallRect, Rect *largeRect, int HOption, int VOption);
  34.     position small rect in large rect */
  35.     
  36. /* GLOBAL: int InitMessage()
  37.     general initialization of message structure */
  38.     
  39. static Rect OriginRect(Rect r);
  40.     /* Moves topleft corner of r to (0,0), while keeping same size, used by ArrangeMessage */ 
  41.  
  42. /* GLOBAL: int ArrangeMessage(int horizontal);
  43.     arranges text, 0…1 icons, 0…3 buttons (horizontally, horizontal = 1; vertical, horizontal = 0)
  44.     returns 1 if fine, 0 if problem */
  45.     
  46. /* GLOBAL: void BoldRect(Rect border);
  47.     Puts bold around a rectangle */
  48.     
  49. static void HandleUpdate(DialogPtr theDialog);
  50.     /* Used to handle update events while a modal dialog is active. Used by FPROC() */
  51.  
  52. static pascal Boolean FProc(DialogPtr theDialog,EventRecord *theEvent,int *itemHit);
  53.     /* Filter procedure called by ModalDialog to screen dialog events */
  54.     
  55. /* GLOBAL: int DoMessage(char *s0, char *s1, char *s2, char *s3);
  56.     main routine for putting up a message box */
  57.     
  58. /* GLOBAL: int Message(int theType, int theIcon, char *s0, char *s1, char *s2, char *s3)
  59.     handles standard M_OK, M_OK_CANCEL, M_YES_NO, M_YES_NO_CANCEL, M_BUTTONLESS dialogs */
  60.     
  61. /* GLOBAL: int SaveChanges(char *s1, char *s2)
  62.     handles standard save changes dialog */
  63.     
  64. /* GLOBAL: char AnOSError(OSErr theError, char *s1, char *s2)
  65.     handles standard OS Error dialog */
  66.     
  67. /*************************************************************/
  68. /* Function Defined */
  69. /*************************************************************/
  70. /* void MenuBar_Hieght(void)
  71.     used to return menu bar height */
  72. int MenuBar_Hieght(void)
  73. {
  74. #define    mBarHeightGlobal 0xBAA
  75. int *MemPtr, theHieght;
  76.  
  77. MemPtr = (int *) mBarHeightGlobal;
  78. if (*MemPtr < 20)
  79.     return(20);
  80. else
  81.     return(*MemPtr);
  82. }
  83.  
  84. /* void GetMInfo(theMInfo)
  85.     used to get current MInfo state; use like GetPort() and SetPort() with SetMInfo() */
  86. void GetMInfo(theMInfo)
  87. DialogInfoPointer theMInfo;
  88. {
  89. theMInfo->defaultItem = MInfo.defaultItem;
  90. theMInfo->Buttons = MInfo.Buttons;
  91. theMInfo->dPlace = MInfo.dPlace;
  92. theMInfo->dIcon = MInfo.dIcon;
  93. theMInfo->IconRect = MInfo.IconRect;
  94. theMInfo->Button1Rect = MInfo.Button1Rect;
  95. theMInfo->Button2Rect = MInfo.Button2Rect;
  96. theMInfo->Button3Rect = MInfo.Button3Rect;
  97. theMInfo->TextRect = MInfo.TextRect;
  98. theMInfo->dRect = MInfo.dRect;
  99. theMInfo->Arrange = MInfo.Arrange;
  100. theMInfo->AddFilter = MInfo.AddFilter;
  101. strcpy((char *) &theMInfo->Button1, (char *) &MInfo.Button1);
  102. strcpy((char *) &theMInfo->Button2, (char *) &MInfo.Button2);
  103. strcpy((char *) &theMInfo->Button3, (char *) &MInfo.Button3);
  104. strcpy((char *) &theMInfo->CharEquiv, (char *) &MInfo.CharEquiv);
  105. } /* end of GetMInfo() */
  106.  
  107. /*************************************************************/
  108.  
  109. /* void SetMInfo(theMInfo)
  110.     used to set current MInfo state; use like GetPort() and SetPort() with GetMInfo() */
  111. void SetMInfo(theMInfo)
  112. DialogInfo theMInfo;
  113. {
  114. MInfo.defaultItem = theMInfo.defaultItem;
  115. MInfo.Buttons = theMInfo.Buttons;
  116. MInfo.dPlace = theMInfo.dPlace;
  117. MInfo.dIcon = theMInfo.dIcon;
  118. theMInfo.IconRect = MInfo.IconRect;
  119. MInfo.Button1Rect = theMInfo.Button1Rect;
  120. MInfo.Button2Rect = theMInfo.Button2Rect;
  121. MInfo.Button3Rect = theMInfo.Button3Rect;
  122. MInfo.TextRect = theMInfo.TextRect;
  123. MInfo.dRect = theMInfo.dRect;
  124. MInfo.Arrange = theMInfo.Arrange;
  125. MInfo.AddFilter = theMInfo.AddFilter;
  126. strcpy((char *) &MInfo.Button1, (char *) &theMInfo.Button1);
  127. strcpy((char *) &MInfo.Button2, (char *) &theMInfo.Button2);
  128. strcpy((char *) &MInfo.Button3, (char *) &theMInfo.Button3);
  129. strcpy((char *) &MInfo.CharEquiv, (char *) &theMInfo.CharEquiv);
  130. } /* end of SetMInfo() */
  131.  
  132. /*************************************************************/
  133.  
  134. /* SetUpButtons() 
  135.     This sets up text for all 3 buttons and character equivalent, number
  136.     of button and default button of dialog */
  137. void SetUpButtons(numButtons, theDefault, b1, b2, b3, cq)
  138. int numButtons;
  139. short theDefault;
  140. char *b1, *b2, *b3, *cq;
  141. {
  142. MInfo.Buttons = numButtons;
  143. MInfo.defaultItem = theDefault;
  144.  
  145. strcpy((char *) &(MInfo.Button1), b1);
  146. strcpy((char *) &(MInfo.Button2), b2);
  147. strcpy((char *) &(MInfo.Button3), b3);
  148. strcpy((char *) &(MInfo.CharEquiv), cq);
  149. } /* end of SetUpButtons(numButtons, theDefault, b1, b2, b3, cq) */
  150.  
  151. /*************************************************************/
  152.  
  153. void SetUpRects(dHor, dVer, bHor, bVer)
  154. int dHor, dVer, bHor, bVer;
  155. {
  156. SetRect(&(MInfo.dRect), 0, 0, dHor, dVer);
  157. SetRect(&(MInfo.Button1Rect), 0, 0, bHor, bVer);
  158. SetRect(&(MInfo.Button2Rect), 0, 0, bHor, bVer);
  159. SetRect(&(MInfo.Button3Rect), 0, 0, bHor, bVer);
  160. } /* end SetUpRects() */
  161.  
  162. /*************************************************************/
  163.  
  164. /* PositionRect()
  165.     Position a smaller rectangle within a larger rectangle 
  166.     Options for horizontal (HOption) and vertical (VOption) are as follows:
  167.         0 : No positioning
  168.         2, CENTER: center small within large
  169.         3, THIRD: position in top (or left) third
  170.     */
  171. void PositionRect(smallRect, largeRect, HOption, VOption)
  172. Rect *smallRect, *largeRect;
  173. int HOption, VOption;
  174. {
  175. int hoffset, voffset;
  176.  
  177. /* position horizontally if requested */
  178. if (HOption != 0) {
  179.     smallRect->right -= smallRect->left;
  180.     smallRect->left = 0;
  181.     hoffset = (largeRect->right - largeRect->left - smallRect->right) / HOption;
  182.     smallRect->left = largeRect->left + hoffset;
  183.     smallRect->right += smallRect->left;
  184.     }
  185.  
  186. /* position vertically if requested */
  187. if (VOption != 0) {
  188.     smallRect->bottom -= smallRect->top;
  189.     smallRect->top = 0;
  190.     voffset = (largeRect->bottom - largeRect->top - smallRect->bottom) / VOption;
  191.     smallRect->top = largeRect->top + voffset;
  192.     smallRect->bottom += smallRect->top;
  193.     }
  194. } /* end of PositionRect(smallRect, largeRect, HOption, VOption) */
  195.  
  196. /*************************************************************/
  197.  
  198. /* InitMessage
  199.     General initialization (centered, stop icon, one button)
  200.     You will need to write your own InitMessage for various messages */
  201. void InitMessage()
  202. {
  203. menu_hieght = MenuBar_Hieght();
  204. MInfo.defaultItem = 1;
  205. MInfo.Buttons = 1;
  206. MInfo.dIcon = stopIcon;
  207. MInfo.dPlace = CENTER;
  208. MInfo.Arrange = HORIZONTAL;
  209. MInfo.AddFilter = NULL;
  210.  
  211. SetRect(&MInfo.dRect, 0, 0, MWidth, MHeight);
  212. PositionRect(&MInfo.dRect, &(screenBits.bounds), CENTER, CENTER);
  213.  
  214. SetRect(&MInfo.IconRect, 15, 15, 47, 47);
  215. SetRect(&MInfo.Button1Rect, 230, 100, 310, 120);
  216. SetRect(&MInfo.Button2Rect, 125, 100, 205, 120);
  217. SetRect(&MInfo.Button3Rect, 20, 100, 100, 120);
  218. SetRect(&MInfo.TextRect, 65, 15, 315, 80);
  219.  
  220. strcpy((char *) &(MInfo.Button1), "\pOk");
  221. strcpy((char *) &(MInfo.Button2), "\pCancel");
  222. strcpy((char *) &(MInfo.Button3), "\pNo");
  223. strcpy((char *) &(MInfo.CharEquiv), "\poOcCnN");
  224. } /* end of InitMessage() */
  225.  
  226. /*************************************************************/
  227.  
  228. static Rect OriginRect(r)
  229. Rect r;
  230. {
  231. Rect newRect;
  232.  
  233. SetRect(&newRect, 0, 0, r.right - r.left, r.bottom - r.top);
  234. return newRect;
  235. } /* end of OriginRect(r) */
  236.  
  237. /*************************************************************/
  238.  
  239. /* ArrangeMessage(); takes MInfo and arranges the rectangles accordingly
  240.     it will look like this:
  241.     __________________       _____________________
  242.     |     _________   |      |     _________      |
  243.     | [I] | Text   |  |      | [I] | Text   | (1) |
  244.     |     |        |  |  or  |     |        |     | according to MInfo.Arrange
  245.     |     |________|  |      |     |        | (2) |
  246.     |                 |      |     |        |     |
  247.     |  (1)  (2)  (3)  |      |     |________| (3) |
  248.     |_________________|      |____________________|
  249.     
  250.     if icon is not around, text is moved over, also if there are no buttons,
  251.     text is moved down.
  252.     
  253.     If all goes well it will return 1, if not, it will return 0 */
  254. int ArrangeMessage()
  255. {
  256. #define MARGIN 10
  257. #define WSPACE 15
  258.  
  259. Rect tRdialog, tRicon, tRtext, tRb1, tRb2, tRb3; /* temporary rectangles */
  260. Rect MaxRect;
  261. int    spacing;
  262.  
  263. /* place rectangles at origin for easier calculations */
  264. tRdialog = OriginRect(MInfo.dRect);
  265. tRicon = OriginRect(MInfo.IconRect);
  266. tRtext = OriginRect(MInfo.TextRect);
  267. tRb1 = OriginRect(MInfo.Button1Rect);
  268. tRb2 = OriginRect(MInfo.Button2Rect);
  269. tRb3 = OriginRect(MInfo.Button3Rect);
  270.  
  271. /* set non-used buttons to (0,0,0,0) */
  272. switch (MInfo.Buttons) {
  273.     case 0:
  274.         SetRect(&tRb1, 0,0,0,0);
  275.     case 1:
  276.         SetRect(&tRb2, 0,0,0,0);
  277.     case 2:
  278.         SetRect(&tRb3, 0,0,0,0);
  279.     default:
  280.         break;
  281.     }
  282.  
  283. /* get max rectangle of buttons */
  284. UnionRect(&tRb1, &tRb2, &MaxRect);
  285. UnionRect(&tRb3, &MaxRect, &MaxRect);
  286.  
  287. tRtext = tRdialog;
  288. InsetRect(&tRtext, MARGIN, MARGIN);
  289.  
  290. if (MInfo.dIcon >= stopIcon) { /* place icon */
  291.     SetRect(&tRicon, 10, 10, 42, 42);
  292.     if ((tRicon.right > tRdialog.right) || (tRicon.bottom > tRdialog.bottom)) {
  293.         return 0;
  294.         }
  295.     /* adjust text for icon and check if there is enough room */
  296.     tRtext.left = tRicon.right + WSPACE;
  297.     if (tRtext.right - tRtext.left < MARGIN) return 0;
  298.     }
  299. else /* no icon */
  300.     SetRect(&tRicon, 0,0,0,0);
  301.     
  302. /* figure spacing for buttons */
  303. if ((MInfo.Buttons > 0) && (MInfo.Arrange == HORIZONTAL)) { /* place buttons horizontally */
  304.     spacing = (tRdialog.right - ((tRb1.right + tRb2.right + tRb3.right) + (MARGIN * 2)))/ (MInfo.Buttons + 1);
  305.  
  306.     /* place buttons */
  307.     SetRect(&tRb1, MARGIN + spacing,
  308.                 tRdialog.bottom - tRb1.bottom - MARGIN,
  309.                 tRb1.right + MARGIN + spacing,
  310.                 tRdialog.bottom - MARGIN);
  311.     SetRect(&tRb2, tRb1.right + spacing,
  312.                 tRdialog.bottom - tRb2.bottom - MARGIN,
  313.                 tRb2.right + tRb1.right + spacing,
  314.                 tRdialog.bottom - MARGIN);
  315.     SetRect(&tRb3, tRb2.right + spacing,
  316.                 tRdialog.bottom - tRb3.bottom - MARGIN,
  317.                 tRb3.right + tRb2.right + spacing,
  318.                 tRdialog.bottom - MARGIN);
  319.  
  320.     /* adjust text recangle for buttons and check if there is enough text room */
  321.     tRtext.bottom = tRdialog.bottom - MARGIN - MaxRect.bottom - WSPACE;
  322.     if (tRtext.bottom - tRtext.top < MARGIN) return 0;
  323.     }
  324.  
  325. if ((MInfo.Buttons > 0) && (MInfo.Arrange != HORIZONTAL)) { /* place buttons vertically */
  326.     spacing = (tRdialog.bottom - ((tRb1.bottom + tRb2.bottom + tRb3.bottom) + (MARGIN * 2)))/ (MInfo.Buttons + 1);
  327.  
  328.     /* place buttons */
  329.     SetRect(&tRb1, tRdialog.right - MARGIN - tRb1.right,
  330.                 MARGIN + spacing,
  331.                 tRdialog.right - MARGIN,
  332.                 MARGIN + spacing + tRb1.bottom);
  333.     SetRect(&tRb2, tRdialog.right - MARGIN - tRb2.right,
  334.                 tRb1.bottom + spacing,
  335.                 tRdialog.right - MARGIN,
  336.                 tRb1.bottom + spacing + tRb2.bottom);
  337.     SetRect(&tRb3, tRdialog.right - MARGIN - tRb3.right,
  338.                 tRb2.bottom + spacing,
  339.                 tRdialog.right - MARGIN,
  340.                 tRb2.bottom + spacing + tRb3.bottom);
  341.     /* adjust text recangle for buttons and check if there is enough text room */
  342.     tRtext.right = tRdialog.right - MARGIN - MaxRect.right - WSPACE;
  343.     if (tRtext.right - tRtext.left < MARGIN) return 0;
  344.     }
  345.     
  346. /* return new rectangle values */
  347. MInfo.IconRect = tRicon;
  348. MInfo.TextRect = tRtext;
  349. switch (MInfo.Buttons) {
  350.     case 3:
  351.         MInfo.Button3Rect = tRb3;
  352.     case 2:
  353.         MInfo.Button2Rect = tRb2;
  354.     case 1:
  355.         MInfo.Button1Rect = tRb1;
  356.     default:
  357.         break;
  358.     }
  359.  
  360. return 1;
  361. } /* end of int ArrangeMessage() */
  362.  
  363. /*************************************************************/
  364.  
  365. /* BoldRect bolds the default button */
  366. void BoldRect(border)
  367. Rect border;
  368. {
  369. PenNormal();
  370. PenSize(lineSize, lineSize);
  371. InsetRect(&border, gapBetween, gapBetween);    
  372. FrameRoundRect(&border, edgeCurve, edgeCurve);
  373. PenNormal();
  374. }
  375.  
  376. /*************************************************************/
  377.  
  378. /* Handle Update function is used for dialog drawing such as the default button */
  379. static void HandleUpdate(theDialog)
  380. DialogPtr theDialog;
  381. {
  382. Rect    itemRect, theRect;
  383. int    itemType;
  384. Handle    the_item;
  385. Handle item;
  386.  
  387. if (MInfo.dIcon >= 0) {
  388.     GetDItem(theDialog, (MInfo.Buttons) + 2, &itemType, &item, &theRect);
  389.     PlotIcon(&theRect, item);
  390.     }
  391.     
  392. if((MInfo.defaultItem > MInfo.Buttons) || (MInfo.defaultItem == 0)) return;
  393.  
  394. GetDItem(theDialog, MInfo.defaultItem, &itemType, &the_item, &itemRect);
  395. BoldRect(itemRect);
  396. } /* end of HandleUpdate() */
  397.  
  398. /*************************************************************/
  399.  
  400. /* FProc is used for filtering Dialog events
  401.     Possible uses include:
  402.     1. Keyboarde Equivalents for controls.
  403.     2. Disk initialization.
  404.     3. Refreshing drawings such as default buttons.
  405.     4. Mouse tracking.
  406.     
  407.     Returning TRUE means ModalDialog will exit, False means no */
  408.  
  409. static pascal Boolean FProc(theDialog,  theEvent, itemHit)
  410. DialogPtr    theDialog;
  411. EventRecord    *theEvent;
  412. int    *itemHit;
  413. {
  414. long    key;            /* Holds the key code */
  415. Point    ctr;            /* where the mouse click will go */
  416. int    DIResult;        /* Returned by DIBadMount */
  417. EventRecord    diskEvent;        /* Returned by EventAvail, below */
  418.  
  419. /* Handle disk mounts */
  420. if (GetNextEvent(diskMask, &diskEvent) == TRUE) {
  421.     if (HiWord(diskEvent.message) != 0) {
  422.         diskEvent.where.h = ((screenBits.bounds.right - 
  423.             screenBits.bounds.left) / 2) - (304 / 2);
  424.         diskEvent.where.v = ((screenBits.bounds.bottom - 
  425.             screenBits.bounds.top) / 3) - (104 / 2);
  426.         InitCursor();
  427.         DIResult = DIBadMount(diskEvent.where, diskEvent.message);
  428.         }
  429.     }    /* end of if GetNextEvent test for disk events */
  430.  
  431. switch (theEvent->what) {
  432.     case (updateEvt):
  433.             HandleUpdate(theDialog);
  434.             return FALSE;
  435.             break;    
  436.                             
  437.     case (keyDown):
  438.             key = theEvent->message & charCodeMask;
  439.             switch(key) {    
  440.             /* If a key has been pressed, we want to interpret it properly. */
  441.                 case theReturnKey: /* Return key */
  442.                 case theEnterKey: /* the Enter key */                                
  443.                     *itemHit = MInfo.defaultItem;
  444.                     return TRUE; /* exit ModalDialog */
  445.                 
  446.                 /* Put in other Key equivalents, you may wish to check modifies */
  447.                 default:
  448.                     if ((MInfo.Buttons > 0) && (theEvent->modifiers & cmdKey))
  449.                         if ((key == MInfo.CharEquiv[1]) || (key == MInfo.CharEquiv[2])) {
  450.                             *itemHit = 1;
  451.                             return TRUE;
  452.                             }
  453.                     if ((MInfo.Buttons > 1) && (theEvent->modifiers & cmdKey))
  454.                         if ((key == MInfo.CharEquiv[3]) || (key == MInfo.CharEquiv[4])) {
  455.                             *itemHit = 2;
  456.                             return TRUE;
  457.                             }
  458.                     if ((MInfo.Buttons > 2) && (theEvent->modifiers & cmdKey))
  459.                         if ((key == MInfo.CharEquiv[5]) || (key == MInfo.CharEquiv[6])) {
  460.                             *itemHit = 3;
  461.                             return TRUE;
  462.                             }
  463.                     SysBeep(5);
  464.                     return FALSE;
  465.                 }    /* end of key code switch */
  466.             break;
  467.             
  468.     case (mouseDown):
  469.                 /* You can insert your own mouse click
  470.                     handlers here.  ModalDialog 
  471.                     takes care of mouse events, but you can do
  472.                     do special processing.  For example,
  473.                     ModalDialog does nothing if a mouse click
  474.                     occurs inside a modal dialog but outside
  475.                     of a control, but you could do something.
  476.                     Keep in mind that you need to wait for 
  477.                     mouseUp to determine where the click was 
  478.                     completed. This gets complex when you 
  479.                     remember that this procedure is not in 
  480.                     control, but gets sent each event to filter 
  481.                     and/or act upon. You would have to use
  482.                     static variables to hold events that you
  483.                     want to keep track of between calls to
  484.                     your filterProc. */
  485.             
  486.             /* if there are no buttons, dismiss dialog with a mouse click */
  487.             if (MInfo.Buttons == 0) {
  488.                 *itemHit = MInfo.defaultItem;
  489.                 return TRUE;
  490.                 }
  491.             return FALSE;
  492.             break;
  493.             
  494.     case (mouseUp):
  495.             return FALSE;
  496.             break;
  497.             
  498.     default:
  499.             return FALSE;
  500.             break;        
  501.             /* We don't handle any other types of events, so
  502.                 these get sent to ModalDialog unchanged. */
  503.         
  504.     }    /* end of switch */
  505.                     
  506. } /* end of filterproc function */
  507.  
  508. /*************************************************************/
  509.  
  510. /* Do Message is a function to handle various 0-3 button message dialogs 
  511.     returns last item hit in dialog or 0 if something went wrong */
  512. int DoMessage( s0, s1, s2, s3)
  513. char *s0, *s1, *s2, *s3;
  514. {
  515. int itemHit, itemNo, itemType;
  516. int exitDialog, DLOGno;
  517. Rect theRect;
  518. DialogPtr theDialog;
  519. Handle theDITL, item, icon;
  520. DialogTHndl dth;
  521. WindowPtr oldWindow;
  522.  
  523. /* get icon if needed */
  524. DLOGno = MessageBase + MInfo.Buttons;
  525. if (MInfo.dIcon >= 0) {
  526.     DLOGno += 10;
  527.     icon = GetIcon(MInfo.dIcon);
  528.     if (icon == NULL)
  529.         SysBeep(5);
  530.     if (ResError() != noErr) return (0);
  531.     HLock(icon);
  532.     }
  533.  
  534. dth = (DialogTHndl) GetResource('DLOG', DLOGno);
  535. if (ResError() != noErr) return(0);
  536. HLock((Handle) dth);
  537.  
  538. GetPort(&oldWindow);
  539.  
  540. theRect = screenBits.bounds;
  541. theRect.top += menu_hieght;
  542. if ((MInfo.dPlace == CENTER) || (MInfo.dPlace == THIRD))
  543.     PositionRect(&(MInfo.dRect), &(theRect), CENTER, MInfo.dPlace);
  544.  
  545. /* set up DLOG template's bounds rectangle */
  546. (*dth)->boundsRect = MInfo.dRect;
  547.  
  548. theDialog = GetNewDialog(DLOGno, 0, (WindowPtr) -1); /*will get modified rect*/
  549. if (theDialog == NULL) {
  550.     SetPort(oldWindow);
  551.     HUnlock((Handle) dth);
  552.     ReleaseResource((Handle) dth);
  553.     return (0);
  554.     }
  555.  
  556. /* arrange the dialog items in MInfo */
  557. if (ArrangeMessage() == 0) return (0);
  558.  
  559. /* set up title buttons */
  560. switch (MInfo.Buttons) {
  561.     case 3:
  562.         GetDItem(theDialog, 3, &itemType, &item, &theRect);
  563.         SetCTitle((ControlHandle) item, MInfo.Button3);
  564.         theRect = MInfo.Button3Rect;
  565.         (**((ControlHandle)item)).contrlRect = theRect;
  566.         SetDItem(theDialog, 3, itemType, item, &theRect);
  567.     case 2:
  568.         GetDItem(theDialog, 2, &itemType, &item, &theRect);
  569.         SetCTitle((ControlHandle) item, MInfo.Button2);
  570.         theRect = MInfo.Button2Rect;
  571.         (**((ControlHandle)item)).contrlRect = theRect;
  572.         SetDItem(theDialog, 2, itemType, item, &theRect);
  573.     case 1:
  574.         GetDItem(theDialog, 1, &itemType, &item, &theRect);
  575.         SetCTitle((ControlHandle) item, MInfo.Button1);
  576.         theRect = MInfo.Button1Rect;
  577.         (**((ControlHandle)item)).contrlRect = theRect;
  578.         SetDItem(theDialog, 1, itemType, item, &theRect);
  579.     default:
  580.         break;
  581.     }
  582.     
  583. /* set up icon if needed */
  584. if (MInfo.dIcon >= 0) {
  585.     GetDItem(theDialog, (MInfo.Buttons) + 2, &itemType, &item, &theRect);
  586.     theRect = MInfo.IconRect;
  587.     item = icon;
  588.     SetDItem(theDialog, (MInfo.Buttons) + 2, itemType, item, &theRect);
  589.     }
  590.     
  591. /* set up text */
  592. GetDItem(theDialog, MInfo.Buttons + 1, &itemType, &item, &theRect);
  593. theRect = MInfo.TextRect;
  594. SetDItem(theDialog, MInfo.Buttons + 1, itemType, item, &theRect);
  595. ParamText(s0, s1, s2, s3);
  596.  
  597. /* set up exit flag and do Modal Dialog */
  598. exitDialog = FALSE;
  599. ShowWindow(theDialog);
  600. SelectWindow(theDialog);
  601. SetPort(theDialog);
  602. FlushEvents(everyEvent, 0);
  603.  
  604. /* Actual Dialog Loop */
  605. while (!exitDialog) {
  606.     ModalDialog((ProcPtr) FProc, &itemHit);
  607.     
  608.     /* further checks and handling */
  609.     if (MInfo.AddFilter == NULL) {
  610.         if (itemHit <= MInfo.Buttons) exitDialog = TRUE; /* exit on any button pressed */
  611.         }
  612.     else {
  613.         exitDialog = CallPascalB(itemHit, theDialog, MInfo.AddFilter);
  614.         }
  615.         
  616.     if (itemHit == MInfo.defaultItem) exitDialog = TRUE; /* exit on default item */
  617.     }
  618.  
  619. /* dispose of resources */
  620. DisposDialog(theDialog);
  621. if (icon != NULL) {
  622.     HUnlock(icon);
  623.     ReleaseResource(icon);
  624.     }
  625. HUnlock((Handle) dth);
  626. ReleaseResource((Handle) dth);
  627. SetPort(oldWindow);
  628. return itemHit;
  629. } /* end of DoMessage( s0, s1, s2, s3) */
  630.  
  631. /*************************************************************/
  632.  
  633. /* Message() Handles standard ok, ok/cancel, yes/no,
  634. yes/no/cancel dialogs */
  635. int Message(theType, theIcon, s0, s1, s2, s3)
  636. int theType, theIcon;
  637. char *s0, *s1, *s2, *s3;
  638. {
  639. DialogInfo    tempInfo, oldInfo; /* MInfo stuff */
  640. int    theAnswer;
  641. WindowPtr savePort;
  642.  
  643. GetMInfo(&oldInfo);
  644.  
  645. tempInfo.dIcon = theIcon;
  646. tempInfo.Arrange = HORIZONTAL;
  647. tempInfo.AddFilter = NULL;
  648. tempInfo.dPlace = THIRD;
  649. SetMInfo(tempInfo);
  650.  
  651. switch (theType) {
  652.     case M_BUTTONLESS:
  653.         SetUpButtons(0, 0, "\p", "\p", "\p", "\p");
  654.         SetUpRects(250, 100, 0, 0);
  655.         break;
  656.     case M_OK:
  657.         SetUpButtons(1, 1, "\pOK", "\p", "\p", "\pOoOoOo");
  658.         SetUpRects(250, 150, 60, 20);
  659.         break;
  660.     case M_OK_CANCEL:
  661.         SetUpButtons(2, 1, "\pOK", "\pCancel", "\p", "\pOoCcOo");
  662.         SetUpRects(250, 150, 60, 20);
  663.         break;
  664.     case M_YES_NO:
  665.         SetUpButtons(2, 1, "\pYes", "\pNo", "\p", "\pYyNnOo");
  666.         SetUpRects(250, 150, 60, 20);
  667.         break;
  668.     case M_YES_NO_CANCEL:
  669.         SetUpButtons(3, 1, "\pYes", "\pNo", "\pCancel", "\pYyNnCc");
  670.         SetUpRects(300, 150, 60, 20);
  671.         break;
  672.     default:;
  673.     }
  674.  
  675. GetPort(&savePort);
  676. theAnswer = DoMessage(s0, s1, s2, s3);
  677. SetPort(savePort);
  678. SetMInfo(oldInfo);
  679. return(theAnswer);
  680. } /* end Message() */
  681.  
  682. /*************************************************************/
  683.  
  684. /* SaveChanges() Handles standard yes/no/cancel.
  685. "Save changes to
  686. <FileName>
  687. <before closing? | before quitting?>" */
  688. int SaveChanges(s1, s2)
  689. char *s1, *s2;
  690. {
  691. int theAnswer;
  692.  
  693. theAnswer = Message(M_YES_NO_CANCEL, cautionIcon, "\pSave changes to", s1, s2, "\p");
  694.  
  695. return(theAnswer);
  696. } /* end SaveChanges() */
  697.  
  698. /*************************************************************/
  699.  
  700. /* AnOSError() Handles OS error reporting.
  701. Returns TRUE if error, else FALSE (no error) */
  702. char AnOSError(theError, s1, s2)
  703. OSErr theError;
  704. char *s1, *s2;
  705. {
  706. char anError;
  707. Str255 s4;
  708. int theAnswer;
  709.  
  710. anError = FALSE;
  711. if (theError != noErr) {
  712.     InitCursor();
  713.     anError = TRUE;
  714.     NumToString((long) theError, &s4);
  715.     theAnswer = Message(M_OK, noteIcon,  s1, s2, "\pOS error # is", (char *) &s4);
  716.     }
  717. return(anError);
  718. }